public class Matrix {
    private double[][] data;

    // Task 1: Matrix Class Implementation
    public Matrix(double[][] data) {
        if (data == null || !isProper2DArray(data)) {
            throw new IllegalArgumentException("Invalid matrix data");
        }
        this.data = new double[data.length][];
        for (int i = 0; i < data.length; i++) {
            this.data[i] = data[i].clone();
        }
    }

    // Helper method to check if the 2D array has proper dimensions
    private boolean isProper2DArray(double[][] array) {
        if (array.length == 0) return false;
        for (double[] row : array) {
            if (row == null || row.length != array[0].length) return false;
        }
        return true;
    }

    // Task 2: Accessor Method
    public double[][] getData() {
        double[][] copy = new double[data.length][];
        for (int i = 0; i < data.length; i++) {
            copy[i] = data[i].clone();
        }
        return copy;
    }

    // Task 3: Matrix Addition
    public Matrix add(Matrix other) {
        if (this.data.length != other.data.length || this.data[0].length != other.data[0].length) {
            throw new IllegalArgumentException("Matrices must be the same size for addition");
        }
        double[][] sum = new double[this.data.length][];
        for (int i = 0; i < this.data.length; i++) {
            sum[i] = new double[this.data[i].length];
            for (int j = 0; j < this.data[i].length; j++) {
                sum[i][j] = this.data[i][j] + other.data[i][j];
            }
        }
        return new Matrix(sum);
    }

    // Task 4: Matrix Subtraction
    public Matrix subtract(Matrix other) {
        if (this.data.length != other.data.length || this.data[0].length != other.data[0].length) {
            throw new IllegalArgumentException("Matrices must be the same size for subtraction");
        }
        double[][] difference = new double[this.data.length][];
        for (int i = 0; i < this.data.length; i++) {
            difference[i] = new double[this.data[i].length];
            for (int j = 0; j < this.data[i].length; j++) {
                difference[i][j] = this.data[i][j] - other.data[i][j];
            }
        }
        return new Matrix(difference);
    }

    // Task 5: Matrix Multiplication
    public Matrix multiply(Matrix other) {
        if (this.data[0].length != other.data.length) {
            throw new IllegalArgumentException("Number of columns in the first matrix must match the number of rows in the second matrix for multiplication");
        }
        double[][] product = new double[this.data.length][other.data[0].length];
        for (int i = 0; i < this.data.length; i++) {
            for (int j = 0; j < other.data[0].length; j++) {
                for (int k = 0; k < this.data[0].length; k++) {
                    product[i][j] += this.data[i][k] * other.data[k][j];
                }
            }
        }
        return new Matrix(product);
    }

    // Task 6: Matrix Transposition
    public Matrix transpose() {
        double[][] transposed = new double[this.data[0].length][this.data.length];
        for (int i = 0; i < this.data.length; i++) {
            for (int j = 0; j < this.data[i].length; j++) {
                transposed[j][i] = this.data[i][j];
            }
        }
        return new Matrix(transposed);
    }

    // Task 7: Matrix Determinant
    public double determinant() {
        if (this.data.length != this.data[0].length) {
            throw new IllegalArgumentException("Matrix must be square for determinant calculation");
        }
        switch (this.data.length) {
            case 1:
                return this.data[0][0];
            case 2:
                return this.data[0][0] * this.data[1][1] - this.data[0][1] * this.data[1][0];
            default: // For matrices larger than 3x3, return Double.NaN
                return Double.NaN;
        }
    }

    // Example usage
    public static void main(String[] args) {
        double[][] data1 = {{1, 2}, {3, 4}};
        double[][] data2 = {{5, 6}, {7, 8}};
        Matrix matrix1 = new Matrix(data1);
        Matrix matrix2 = new Matrix(data2);
        Matrix sum = matrix1.add(matrix2);
        Matrix difference = matrix1.subtract(matrix2);
        // You can print the matrices or their determinants here if needed
    }
}